package com.iso8583;

import java.io.ByteArrayOutputStream;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Iso8583Composer {
    private static Logger log = LoggerFactory.getLogger(Iso8583Composer.class);
    private final static int BITMAP_LENGTH = 128;
    public  byte[]  compose(String mustFields,String optionalFields,String typeCode,Map<String,String> msg,String suffix,boolean isComposeHead) {
        Iso8583 iso8583 = null;
        try{
            Iso8583Configuration aa = new Iso8583Configuration();

            iso8583 = aa.getIso8583(suffix);
        }catch(Exception e){
            e.printStackTrace();
        }finally{

        }
        char[] bitMapByte = StringUtils.repeat("0", BITMAP_LENGTH).toCharArray();
        ByteArrayOutputStream out = new ByteArrayOutputStream(128);
        String fields = mustFields+"|"+optionalFields;
        String[] filedArray = StringUtils.split(fields, "\\|");
        int[] filedArray2 = new int[filedArray.length];
        for(int i = 0;i<filedArray.length;i++){
            filedArray2[i] = Integer.valueOf(filedArray[i]);
        }
        Arrays.sort(filedArray2);
        // convert to 8583 msg
        convertToPlain(msg, out, bitMapByte, filedArray2, iso8583);
        int bodyLen = 0;
        // add msgTypCod

        // byte[] msgTypByte = HiPack8583Helper.fitPlain(HiItemHelper
        // .execExpression(msg, type_code).getBytes(), msgTypCodNode, log);
        Item8583 msgItem = iso8583.getBody().get(0);
        byte[] msgTypByte = fitPlain(typeCode.getBytes(), msgItem, log);
        bodyLen = msgTypByte.length;

        // add bitmap
        String bitMap = null;
//		if (BITMAP_LENGTH == 128) {
//			bitMapByte[0] = '1';
//			bitMap = AsciiCodec.binary2hex(new String(bitMapByte));
//		} else if (BITMAP_LENGTH == 64) {
//			bitMapByte[0] = '0';
//			bitMap = AsciiCodec.binary2hex(new String(bitMapByte, 0, 64));
//		} else {
        // λͼ�ĳ���,Ĭ�ϰ�ʵ�����, ����һλΪ0λ��Ϊ64λ��
        if (bitMapByte[0] == '0') {
            bitMap = AsciiCodec.binary2hex(new String(bitMapByte, 0, 64));
        } else {
            bitMap = AsciiCodec.binary2hex(new String(bitMapByte));
        }
//		}
        byte[] headByte = null;
        if (isComposeHead) {
            ByteArrayOutputStream hOut = new ByteArrayOutputStream(64);
            packHeader(msg, hOut, iso8583);
            headByte = hOut.toByteArray();
        }
        AsciiCodec bb = new  AsciiCodec();
        byte[] outMapByte = bb.ascStr2Bcd(bitMap);
        bodyLen += outMapByte.length;

        // add 8583 plain
        byte[] outByte = out.toByteArray();
        bodyLen += outByte.length;
        byte[] tmp = ArrayUtils.addAll(headByte, msgTypByte);
        tmp = ArrayUtils.addAll(tmp, outMapByte);
        return (byte[]) ArrayUtils.addAll(tmp, outByte);

        // pack 8583 header
        // if (this.pack_header) {
        // ByteArrayOutputStream hOut = new ByteArrayOutputStream(64);
        // packHeader(ctx, hOut, bodyLen, log);
        // byte[] hOutByte = hOut.toByteArray();
        //
        // // add header byte
        // plainOut.append(hOutByte, 0, hOutByte.length);
        // }

        // add body plain byte
		/*
		 * plainOut.append(msgTypByte, 0, msgTypByte.length);
		 * plainOut.append(outMapByte, 0, outMapByte.length);
		 * plainOut.append(outByte, 0, outByte.length);
		 */

        // save to HiMessage header
        // msg.setHeadItem(HiConstants.PLAIN_TEXT, plainOut);

		/*
		 * if (log.isInfoEnabled()) {
		 * log.info(sm.getString("HiPack8583.processOk", bitMap, plainOut
		 * .toString())); }
		 *
		 * if (log.isDebugEnabled()) {
		 * log.debug("Pack8583: OK =======================");
		 * log.debug("Pack8583: bitMap [" + bitMap + "]");
		 * log.debug("Pack8583: pack [" + plainOut.toString() + "]");
		 * log.debug("doProcess(HiMessageContext) - end."); }
		 */
    }
    public  byte[]  composeYinSheng(String mustFields,String optionalFields,String typeCode,Map<String,String> msg,String suffix,boolean isComposeHead) {
        Iso8583 iso8583 = null;
        try{
            Iso8583Configuration aa = new Iso8583Configuration();
            iso8583 = aa.getIso8583(suffix);
        }catch(Exception e){
            e.printStackTrace();
        }finally{

        }
        char[] bitMapByte = StringUtils.repeat("0", BITMAP_LENGTH).toCharArray();
        ByteArrayOutputStream out = new ByteArrayOutputStream(128);
        String fields = mustFields+"|"+optionalFields;
        String[] filedArray = StringUtils.split(fields, "\\|");
        int[] filedArray2 = new int[filedArray.length];
        for(int i = 0;i<filedArray.length;i++){
            filedArray2[i] = Integer.valueOf(filedArray[i]);
        }
        Arrays.sort(filedArray2);
        // convert to 8583 msg
        convertToPlainYinSheng(msg, out, bitMapByte, filedArray2, iso8583);
        int bodyLen = 0;
        // add msgTypCod

        // byte[] msgTypByte = HiPack8583Helper.fitPlain(HiItemHelper
        // .execExpression(msg, type_code).getBytes(), msgTypCodNode, log);
        Item8583 msgItem = iso8583.getBody().get(0);
        byte[] msgTypByte = fitPlainYinSheng(typeCode.getBytes(), msgItem, log);
        bodyLen = msgTypByte.length;
        String bitMap = null;
        if (bitMapByte[0] == '0') {
            bitMap = AsciiCodec.binary2hex(new String(bitMapByte, 0, 64));
        } else {
            bitMap = AsciiCodec.binary2hex(new String(bitMapByte));
        }
//		}
        byte[] headByte = null;
        if (isComposeHead) {
            ByteArrayOutputStream hOut = new ByteArrayOutputStream(64);
            packHeader(msg, hOut, iso8583);
            headByte = hOut.toByteArray();
        }
        AsciiCodec bb = new  AsciiCodec();
        byte[] outMapByte = bb.ascStr2Bcd(bitMap);
        bodyLen += outMapByte.length;

        // add 8583 plain
        byte[] outByte = out.toByteArray();
        bodyLen += outByte.length;
        byte[] tmp = ArrayUtils.addAll(headByte, msgTypByte);
        tmp = ArrayUtils.addAll(tmp, outMapByte);
        return (byte[]) ArrayUtils.addAll(tmp, outByte);
    }
    private  void convertToPlain(Map<String, String> ctx,
                                 ByteArrayOutputStream out, char[] bitMapByte, int[] packetFiledId,Iso8583 iso8583)
            throws Iso8583Exception {

        Item8583 itemNode;
        String fldName;
        String fldVal;
        byte[] valByte;
        Integer bitIdx;
        int idx = 0;

        for (int fieldId : packetFiledId) {
            idx = fieldId - 1;

            if (BITMAP_LENGTH == 64 && idx >= 64) {
                // ֻ��64λ
                break;
            }
            try{
                itemNode = iso8583.getBody().get(fieldId);

                fldName = itemNode.getPropertyName();
                fldVal = ctx.get(fldName);
                // if (fldVal == null) {
                // //�����ж�
                // if (mustSet.contains(bitIdx)) {
                // throw new
                // Iso8583Exception(itemNode.getFieldId()+itemNode.getPropertyName()+"������ֵ");
                // } else {
                // continue;
                // }
                // }
                if (fldVal == null) {continue;}
                if (StringUtils.equals(itemNode.getConvertor(), "hex"))
                {
                    AsciiCodec bb = new  AsciiCodec();
                    valByte = bb.ascStr2Bcd(fldVal);
                }
                else{
                    valByte = fldVal.getBytes();
                }

                valByte = fitPlain(valByte, itemNode, log);

                out.write(valByte, 0, valByte.length);

                bitMapByte[idx] = '1';
//			log.info("packItemOk" + "|" + fldName + "|"
//					+ String.valueOf(idx + 1) + "|"
//					+ String.valueOf(valByte.length) + "|"
//					+ new String(valByte));
            }catch(Exception e){
                log.error(fieldId+"===========");
                e.printStackTrace();
            }
        }

        // 大于64域则位图首位置为“1”
        if (idx >= 64 && bitMapByte[0] == '0') {
            bitMapByte[0] = '1';
        }
    }
    private  void convertToPlainYinSheng(Map<String, String> ctx,
                                 ByteArrayOutputStream out, char[] bitMapByte, int[] packetFiledId,Iso8583 iso8583)
            throws Iso8583Exception {

        Item8583 itemNode;
        String fldName;
        String fldVal;
        byte[] valByte;
        Integer bitIdx;
        int idx = 0;

        for (int fieldId : packetFiledId) {
            idx = fieldId - 1;

            if (BITMAP_LENGTH == 64 && idx >= 64) {
                // ֻ��64λ
                break;
            }
            try{
                itemNode = iso8583.getBody().get(fieldId);

                fldName = itemNode.getPropertyName();
                fldVal = ctx.get(fldName);
                // if (fldVal == null) {
                // //�����ж�
                // if (mustSet.contains(bitIdx)) {
                // throw new
                // Iso8583Exception(itemNode.getFieldId()+itemNode.getPropertyName()+"������ֵ");
                // } else {
                // continue;
                // }
                // }
                if (fldVal == null) {continue;}
                if (StringUtils.equals(itemNode.getConvertor(), "hex"))
                {
                    AsciiCodec bb = new  AsciiCodec();
                    valByte = bb.ascStr2Bcd(fldVal);
                }
                else{
                    valByte = fldVal.getBytes();
                }

                valByte = fitPlainYinSheng(valByte, itemNode, log);

                out.write(valByte, 0, valByte.length);

                bitMapByte[idx] = '1';
//			log.info("packItemOk" + "|" + fldName + "|"
//					+ String.valueOf(idx + 1) + "|"
//					+ String.valueOf(valByte.length) + "|"
//					+ new String(valByte));
            }catch(Exception e){
                log.error(fieldId+"===========");
                e.printStackTrace();
            }
        }

        // 大于64域则位图首位置为“1”
        if (idx >= 64 && bitMapByte[0] == '0') {
            bitMapByte[0] = '1';
        }
    }

    private  void packHeader(Map<String, String> ctx,ByteArrayOutputStream out,Iso8583 iso8583)  {
        List<Item8583> headerRoot = iso8583.getHead();
        String fldName;
        String fldVal;
        byte[] valByte;
        for(Item8583 itemNode:headerRoot){
            fldName = itemNode.getPropertyName();
            fldVal = ctx.get(fldName);
            if (StringUtils.isNotBlank(fldVal)){
                valByte = fitPlain(fldVal.getBytes(), itemNode, log);

                out.write(valByte, 0, valByte.length);
            }

//	 log.info("HiPack8583.packItemOk", fldName, String.valueOf(valByte.length), new String(valByte));
        }

        if (log.isInfoEnabled()) {
//	 log.info("<==============Pack 8583 Header End");
        }
    }

    // private synchronized void initCfgNode(HiMessageContext ctx)
    // throws HiException {
    // if (isInit) {
    // return;
    // }
    //
    // Logger log = HiLog.getLogger(ctx.getCurrentMsg());
    // if (log.isDebugEnabled()) {
    // log.debug("first initCfgNode - start.");
    // }
    //
    // Element cfgRoot = (Element) ctx.getProperty(HiConstants.CFG8583_NODE);
    // if (cfgRoot == null) {
    // throw new HiException(HiMessageCode.ERR_PACK8583_CFGNODE, "");
    // }
    //
    // msgTypCodNode = HiXmlHelper.selectSingleNode(cfgRoot,
    // HiConstants.CFG8583_ITEM_NAME,
    // HiConstants.CFG8583_ITEM_FIELD_ID, "0");
    // // bitMapNode = HiXmlHelper.selectSingleNode(cfgRoot,
    // // HiConstants.CFG8583_ITEM_NAME, HiConstants.CFG8583_ITEM_FIELD_ID,
    // // "1");
    // // bitMapLen =
    // //
    // Integer.parseInt(bitMapNode.attributeValue(HiConstants.CFG8583_ITEM_LENGTH));
    //
    // itemNodeMap.clear();
    //
    // putMapNode(cfgRoot, mustSet);
    // putMapNode(cfgRoot, optSet);
    //
    // checkHeaderCfg(cfgRoot);
    //
    // isInit = true;
    //
    // if (log.isDebugEnabled()) {
    // log.debug("must_fields [" + this.must_fields + "]");
    // log.debug("opt_fields [" + this.opt_fields + "]");
    // log.debug("first initCfgNode - end.");
    // }
    // }

    // private void putMapNode(Element cfgRoot, Set fieldSet) throws HiException
    // {
    // Element itemNode;
    // Integer fieldIdx;
    //
    // Iterator it = fieldSet.iterator();
    // while (it.hasNext()) {
    // fieldIdx = (Integer) it.next();
    //
    // itemNode = HiXmlHelper.selectSingleNode(cfgRoot,
    // HiConstants.CFG8583_ITEM_NAME,
    // HiConstants.CFG8583_ITEM_FIELD_ID, fieldIdx.toString());
    // if (itemNode == null) {
    // throw new HiException(HiMessageCode.INVALID_PACK8583_FIELD_ID,
    // String.valueOf(fieldIdx));
    // }
    //
    // itemNodeMap.put(fieldIdx, itemNode);
    //
    // }
    // }
    //
    // private void checkValidField(String fields, HashSet fldSet)
    // throws HiException {
    // Integer idx;
    // StringTokenizer tokenizer = new StringTokenizer(fields, "|");
    // while (tokenizer.hasMoreElements()) {
    // try {
    // idx = Integer.valueOf(tokenizer.nextToken());
    //
    // fldSet.add(idx);
    //
    // } catch (NumberFormatException ne) {
    // throw new HiException(HiMessageCode.INVALID_PACK8583_FIELDS,
    // getNodeName(), fields);
    // }
    // if (idx.intValue() <= 1 || idx.intValue() > bitMapLen) {
    // throw new HiException(HiMessageCode.TOOBIG_PACK8583_FIELD_ID,
    // fields);
    // }
    // }
    // }
    //
    // /**
    // * ���������鱨��ͷ������Ƿ�������Header�ڵ�
    // *
    // * @param cfgRoot
    // * @throws HiException
    // */
    // private void checkHeaderCfg(Element cfgRoot) throws HiException {
    // if (this.pack_header) {
    // headerRoot = HiXmlHelper.selectSingleNode(cfgRoot, "Header");
    // if (headerRoot == null) {
    // throw new HiException("", "8583�����ļ�û��Header���ýڵ�");
    // }
    //
    // // ���mLen_pos,hLen_pos
    // Element item;
    // if (hLen_pos != null) {
    // // item = HiXmlHelper.selectSingleNode(cfgRoot,
    // // HiConstants.CFG8583_ITEM_NAME,
    // // HiConstants.CFG8583_ITEM_FIELD_ID, hLen_pos);
    // item = HiXmlHelper.selectSingleNode(headerRoot,
    // HiConstants.CFG8583_ITEM_NAME,
    // HiConstants.CFG8583_ITEM_FIELD_ID, hLen_pos);
    // if (item == null) {
    // throw new HiException("", "8583�����ļ�û�и����ýڵ� field_id:"
    // + hLen_pos);
    // }
    // hLen_name = item
    // .attributeValue(HiConstants.CFG8583_ITEM_ETF_NAME);
    // // Ԥ���㱨��ͷ�ĳ���;header_len����Ϊ-1��Ԥ������,����Ҫ����
    // if (this.header_len == -1) {
    // this.header_len = countHeaderLen();
    // }
    // }
    //
    // if (mLen_pos != null) {
    // // item = HiXmlHelper.selectSingleNode(cfgRoot,
    // // HiConstants.CFG8583_ITEM_NAME,
    // // HiConstants.CFG8583_ITEM_FIELD_ID, mLen_pos);
    // item = HiXmlHelper.selectSingleNode(headerRoot,
    // HiConstants.CFG8583_ITEM_NAME,
    // HiConstants.CFG8583_ITEM_FIELD_ID, mLen_pos);
    // if (item == null) {
    // throw new HiException("", "8583�����ļ�û�и����ýڵ� field_id:"
    // + mLen_pos);
    // }
    // mLen_name = item
    // .attributeValue(HiConstants.CFG8583_ITEM_ETF_NAME);
    // }
    // }
    //
    // }

    // private int countHeaderLen() {
    // if (headerRoot == null) {
    // return 0;
    // }
    // // todo count Header length
    // return 46;
    // }

    /**
     * ������ýڵ㣬��ʽItem����
     *
     * @param valByte
     * @param itemNode
     * @param log
     * @return
     */
    private  byte[] fitPlain(byte[] valByte, Item8583 itemNode, Logger log)
            throws Iso8583Exception {
        String field_id = itemNode.getFieldId();
        String length_type = itemNode.getLengthType();

        String data_type = itemNode.getDataType();

        if (length_type.equals(Iso8583Constants.LENGTH_TYPE_CONST)) {
            int length = Integer.parseInt(itemNode.getLength());
            return fitConstPlain(itemNode, field_id, valByte, data_type,
                    length);
        } else if (length_type.equals(Iso8583Constants.LENGTH_TYPE_VAR2)) {
            return fitVarPlain(itemNode, field_id, valByte, data_type, 2, log);
        } else if (length_type.equals(Iso8583Constants.LENGTH_TYPE_VAR3)) {
            return fitVarPlain(itemNode, field_id, valByte, data_type, 3, log);
        }

        throw new Iso8583Exception("���Ϸ���LENGTH_TYPE" + "��������,field_id["
                + field_id + "], �ó������� length_type[" + length_type + "] ����.");
    }
    /**
     * 银生
     *
     * @param valByte
     * @param itemNode
     * @param log
     * @return
     */
    private  byte[] fitPlainYinSheng(byte[] valByte, Item8583 itemNode, Logger log)
            throws Iso8583Exception {
        String field_id = itemNode.getFieldId();
        String length_type = itemNode.getLengthType();

        String data_type = itemNode.getDataType();

        if (length_type.equals(Iso8583Constants.LENGTH_TYPE_CONST)) {
            int length = Integer.parseInt(itemNode.getLength());
            return fitConstPlain(itemNode, field_id, valByte, data_type,
                    length);
        } else if (length_type.equals(Iso8583Constants.LENGTH_TYPE_VAR2)) {
            return fitVarPlainYinSheng(itemNode, field_id, valByte, data_type, 2, log);
        } else if (length_type.equals(Iso8583Constants.LENGTH_TYPE_VAR3)) {
            return fitVarPlainYinSheng(itemNode, field_id, valByte, data_type, 3, log);
        }

        throw new Iso8583Exception("���Ϸ���LENGTH_TYPE" + "��������,field_id["
                + field_id + "], �ó������� length_type[" + length_type + "] ����.");
    }
    /**
     * �����Ȳ���, ���ָ����align_mode���fill_char; CharASC����, align_modeĬ��Ϊ�����,
     * fill_charΪ�ո�; ��������, align_modeĬ��Ϊ�Ҷ���, fill_ascΪ0;
     *
     * @param itemNode
     * @param field_id
     * @param data_type
     * @param length
     * @return
     */
    private  byte[] fitConstPlain(Item8583 itemNode, final String field_id,
                                  byte[] valBytes, final String data_type, int length)
            throws Iso8583Exception {
        int valLen = valBytes.length;

        // Ĭ�� ��ȡ���೤��
        if (valLen > length) {
            valBytes = ArrayUtils.subarray(valBytes, 0, length);
        }

        // BCDǰ����ݳ���Ϊż��
        if (!data_type.endsWith("ASCII") && length % 2 != 0) {
            length += 1;
        }

        if (valLen < length) {
            // ����ַ�
            // String fill_asc = itemNode.attributeValue("fill_asc");
            String fill_asc = null;
            if (data_type.equals(Iso8583Constants.DATA_TYPE_CHARASCII)) {
                // default �ո� ԭ�ַ������
                valBytes = fillCharRight(valBytes, fill_asc,
                        itemNode.getAlignMode(), length - valLen);

            } else {
                // default 0 ԭ�ַ��Ҷ���
                valBytes = fillCharLeft(valBytes, fill_asc,
                        itemNode.getAlignMode(), length - valLen);
            }
        }

        if (!data_type.endsWith("ASCII")) {
            valBytes = ascStr2Bcd(valBytes);
        }
//		log.info("packet[" + field_id + "]" + new String(valBytes));
        return valBytes;
    }

    /**
     * 1.������ASCBCD��NUMBCDʱ, ����Ϊ����ʱ,���ָ����align_mode���fill_char,align_modeĬ��Ϊ�Ҷ���,
     * fill_ascΪ0; 2.len_type: char��bin, Ĭ��Ϊchar;
     *
     * @param itemNode
     * @param field_id
     * @param data_type
     * @param varLen
     * @param log
     * @return
     */
    private  byte[] fitVarPlain(Item8583 itemNode, final String field_id,
                                byte[] valBytes, final String data_type, final int varLen,
                                Logger log) throws Iso8583Exception {
        // byte[] valBytes = value.getBytes();
        int valueLen = valBytes.length;

        int valueAllocLen = valueLen;
        int varAllocLen = varLen;

        // BCD, ��������ʱ,���㴦��
        if (!data_type.endsWith("ASCII")) {
            if (valueLen % 2 != 0) {
                // default 0 ԭ�ַ��Ҷ���
                valBytes = fillCharLeft(valBytes, null,
                        itemNode.getAlignMode(), 1);
                valueAllocLen += 1;

            }

            valBytes = ascStr2Bcd(valBytes);

            valueAllocLen = valueAllocLen / 2; // �������BCD��ʵ�ʿ��
        } else if (StringUtils.equals(data_type, "CharBinASCII")) {
            AsciiCodec bb = new  AsciiCodec();
            valBytes = bb.ascStr2Bcd(new String(valBytes));
            valueLen = valBytes.length;
            valueAllocLen = valueLen;
        }

        // ǰ�ó���
        String valLenStr = String.valueOf(valueLen);
        if (valLenStr.length() > varLen) {
            throw new Iso8583Exception("�����var_len" + String.valueOf(varLen)
                    + String.valueOf(field_id));
        }

        byte[] valLenBytes;

        if (StringUtils.equals(itemNode.getVarType(),
                Iso8583Constants.VAR_TYPE_BIN)) {
            // ǰ�ó���,ż��,BCD��ʽ
            if (varLen % 2 != 0) {
                varAllocLen += 1;
            }

            if (valLenStr.length() < varAllocLen) {
                valLenStr = StringUtils.leftPad(valLenStr, varAllocLen, '0');
            }
            AsciiCodec bb = new  AsciiCodec();
            valLenBytes = bb.ascStr2Bcd(valLenStr);

            varAllocLen = varAllocLen / 2; // ǰ�ó���bcd���ʵ�ʿ��
        } else {
            if (valLenStr.length() < varLen) {
                valLenStr = StringUtils.leftPad(valLenStr, varLen, '0');
            }

            valLenBytes = valLenStr.getBytes();
        }

        ByteBuffer bb = ByteBuffer.allocate(varAllocLen + valueAllocLen);
        bb.put(valLenBytes);
        bb.put(valBytes);

        return bb.array();
    }
    /**
     *
     * @param itemNode
     * @param field_id
     * @param data_type
     * @param varLen
     * @param log
     * @return
     */
    private  byte[] fitVarPlainYinSheng(Item8583 itemNode, final String field_id,
                                byte[] valBytes, final String data_type, final int varLen,
                                Logger log) throws Iso8583Exception {
        // byte[] valBytes = value.getBytes();
        int valueLen = valBytes.length;

        int valueAllocLen = valueLen;
        int varAllocLen = varLen;

        // BCD, ��������ʱ,���㴦��
        if (!data_type.endsWith("ASCII")) {
            if (valueLen % 2 != 0) {
                // default 0 ԭ�ַ��Ҷ���
                valBytes = fillCharLeft(valBytes, null,
                        itemNode.getAlignMode(), 1);
                valueAllocLen += 1;

            }

            valBytes = ascStr2Bcd(valBytes);

            valueAllocLen = valueAllocLen / 2; // �������BCD��ʵ�ʿ��
        } else if (StringUtils.equals(data_type, "CharBinASCII")) {
            AsciiCodec bb = new  AsciiCodec();
            valBytes = bb.ascStr2Bcd(new String(valBytes));
            valueLen = valBytes.length;
            valueAllocLen = valueLen;
        }

        // ǰ�ó���
        String valLenStr = String.valueOf(valueLen);
        if ("35".equals(itemNode.getFieldId())){
            valLenStr = String.valueOf(valueAllocLen);
        }
        if (valLenStr.length() > varLen) {
            throw new Iso8583Exception("�����var_len" + String.valueOf(varLen)
                    + String.valueOf(field_id));
        }

        byte[] valLenBytes;

        if (StringUtils.equals(itemNode.getVarType(),
                Iso8583Constants.VAR_TYPE_BIN)) {
            // ǰ�ó���,ż��,BCD��ʽ
            if (varLen % 2 != 0) {
                varAllocLen += 1;
            }

            if (valLenStr.length() < varAllocLen) {
                valLenStr = StringUtils.leftPad(valLenStr, varAllocLen, '0');
            }
            AsciiCodec bb = new  AsciiCodec();
            valLenBytes = bb.ascStr2Bcd(valLenStr);

            varAllocLen = varAllocLen / 2; // ǰ�ó���bcd���ʵ�ʿ��
        } else {
            if (valLenStr.length() < varLen) {
                valLenStr = StringUtils.leftPad(valLenStr, varLen, '0');
            }

            valLenBytes = valLenStr.getBytes();
        }

        // ��ϱ䳤����
        ByteBuffer bb = ByteBuffer.allocate(varAllocLen + valueAllocLen);
        bb.put(valLenBytes);
        bb.put(valBytes);

        return bb.array();
    }

    /**
     * ����ַ�, Ĭ�ϴ������0, ԭ�ַ��ҿ�����
     *
     * @param value
     * @param fill_asc
     *            ����ַ��ASC
     * @return
     */
    private  byte[] fillCharLeft(byte[] value, String fill_asc,
                                 String align_mode, int repeat) {
        if (repeat <= 0) {
            return value;
        }
        if (StringUtils.isEmpty(fill_asc)) {
            fill_asc = "48";// default 0��ASC
        }

        byte b = Integer.valueOf(fill_asc).byteValue();
        byte[] fillValue = new byte[value.length + repeat];
        // default �Ҷ���
        if (StringUtils.equals(align_mode, Iso8583Constants.ALIGN_MODE_LEFT)) {
            System.arraycopy(value, 0, fillValue, 0, value.length);
            for (int i = 0; i < repeat; i++) {
                fillValue[value.length + i] = b;
            }
        } else {
            for (int i = 0; i < repeat; i++) {
                fillValue[i] = b;
            }
            System.arraycopy(value, 0, fillValue, repeat, value.length);
        }
        return fillValue;
    }

    /**
     * ����ַ�, Ĭ�ϴ������ո�, ԭ�ַ������
     *
     * @param value
     * @param fill_asc
     *            ����ַ��ASC
     * @return
     */
    private  byte[] fillCharRight(byte[] value, String fill_asc,
                                  String align_mode, int repeat) {
        if (repeat <= 0) {
            return value;
        }
        if (StringUtils.isEmpty(fill_asc)) {
            fill_asc = "32";// default �ո��ASC
        }

        byte b = Integer.valueOf(fill_asc).byteValue();
        byte[] fillValue = new byte[value.length + repeat];

        // default �����
        if (StringUtils.equals(align_mode, Iso8583Constants.ALIGN_MODE_RIGHT)) {
            for (int i = 0; i < repeat; i++) {
                fillValue[i] = b;
            }
            System.arraycopy(value, 0, fillValue, repeat, value.length);
        } else {
            System.arraycopy(value, 0, fillValue, 0, value.length);
            for (int i = 0; i < repeat; i++) {
                fillValue[value.length + i] = b;
            }
        }
        return fillValue;
    }

    public byte[] buildByteMap(String fields){
        String[] filedArray = StringUtils.split(fields, "\\|");
        int[] filedArray2 = new int[filedArray.length];
        for(int i = 0;i<filedArray.length;i++){
            filedArray2[i] = Integer.valueOf(filedArray[i]);
        }
        Arrays.sort(filedArray2);
        char[] bitMapByte = StringUtils.repeat("0", BITMAP_LENGTH).toCharArray();
        int idx = 0;
        for (int fieldId : filedArray2) {
            idx = fieldId - 1;
            bitMapByte[idx] = '1';
        }

        if (idx >= 64 && bitMapByte[0] == '0') {
            bitMapByte[0] = '1';
        }
        String bitMap = null;
        if (bitMapByte[0] == '0') {
            bitMap = AsciiCodec.binary2hex(new String(bitMapByte, 0, 64));
        } else {
            bitMap = AsciiCodec.binary2hex(new String(bitMapByte));
        }
        AsciiCodec bb = new  AsciiCodec();
        byte[] outMapByte = bb.ascStr2Bcd(bitMap);
        return outMapByte;
    }

    public byte [] str2Byte(String str){
        AsciiCodec bb = new  AsciiCodec();
        return bb.ascStr2Bcd(str);
    }
    /**
     *
     * @param bytes
     * @return
     * @throws Iso8583Exception
     */
    private  byte[] ascStr2Bcd(byte[] bytes) throws Iso8583Exception {
        try {
            bytes = AsciiCodec.decodeHex(bytes);
        } catch (CodecException e) {
            throw new Iso8583Exception("" + e);
        }

        return bytes;
    }

}